#ifndef _FEATUREEXTRACTER_H
#define _FEATUREEXTRACTER_H

#include "header.h"

#include <cstdio>

class CharFeature {
public:
    static const int s_NORM_SIZE = 64;

    static const int s_FEATURE_SIZE = 403;

    static CharFeature & getInstance() {
        static CharFeature _instance;
        return _instance;
    }

    /** this method can update the max/min value of each dim in feature */
    void extractFeature(float* data, const uchar* imageData, bool updateMaxMin = false);

    void extractScaledFeature(float* data, const uchar* imageData);

    void scaleFeature(float* feature);

    void saveData();

    ~CharFeature(void) {
    };

#ifdef TEST

    void TEST_calcStrokeWidthAndLen(const char* imageData, int* strokeWidth, int* totalStrokeLen) {
        calcStrokeWidthAndLen(imageData, strokeWidth, totalStrokeLen);
    }

    void TEST_calcProjHist(const char* imageData, int projHist[][s_NORMSIZE]) {
        calcProjHist(imageData, projHist);
    }

    void TEST_calcTransDensAndPeri(const char* imageData, int* transitions, int strokeDensity[][8], int peripheral[][8][2]) {
        calcTransDensAndPeri(imageData, transitions, strokeDensity, peripheral);
    }

    void TEST_calcLocDirPropAndMaxLocDir(const char* imageData, int locDir[][4][4], float strokeProp[][4][4], int maxLocDirCtr[][4][4]) {
        calcLocDirPropAndMaxLocDir(imageData, locDir, strokeProp, maxLocDirCtr);
    }

    void TEST_calcBlackJump(const char* imageData, int totalBlackJump[][8], float divBlackJump[][8]) {
        calcBlackJump(imageData, totalBlackJump, divBlackJump);
    }
#endif

private:

    enum Dir {
        NORTH = 0, SOUTH, WEST, EAST
    };

    enum Line {
        LDOWN_RUP = 0, LUP_RDOWN, LEFT_RIGHT, UP_DOWN
    };

    enum BlackJumpType {
        SUB_TOTAL = 0, SUB_DIVIDED
    };

    enum HV {
        HORIZONTAL = 0, VERTICAL, SLANTING = VERTICAL
    };

    static const int s_STRIPESIZE = 8;

    static const int s_GRIDSIZE = 4;

    static const int s_SUBVCOUNT = 8;

    float m_max[s_FEATURE_SIZE];
    float m_min[s_FEATURE_SIZE];

    CharFeature();

    void calcStrokeWidthAndLen(const uchar* imageData, int* strokeWidth, int* totalStrokeLen);

    void calcProjHist(const uchar* imageData, int projHist[][s_NORM_SIZE]);

    void calcTransDensAndPeri(const uchar* imageData, int* transitions, int strokeDensity[][s_STRIPESIZE], int peripheral[][s_STRIPESIZE][2]);

    void calcLocDirPropAndMaxLocDir(const uchar* imageData, int locDir[][s_GRIDSIZE][4], float strokeProp[][s_GRIDSIZE][4], int maxLocDirCtr[][s_GRIDSIZE][4]);

    void calcBlackJump(const uchar* imageData, int totalBlackJump[][s_SUBVCOUNT], float divBlackJump[][s_SUBVCOUNT]);

};

#endif
